package net

import (
	"context"
	"io"
	"lcnap/flow/cfg"
	"lcnap/flow/log"
	"net"
	"sync"
)

type Server struct {
	Listeners []*ListenerWrapper
	mutex     sync.Mutex
}

var servers *Server

func newServers() *Server {
	if servers == nil {
		return &Server{
			Listeners: make([]*ListenerWrapper, 10),
			mutex:     sync.Mutex{},
		}
	}
	return servers
}

type ListenerWrapper struct {
	Listen   string
	Listener net.Listener

	Context context.Context
	Cancel  context.CancelFunc

	PassFunc func() (net.Conn, error)
}

// 加载文件配置
func InitConfig(cfg cfg.Cfg) {
	s := newServers()
	s.mutex.Lock()
	defer s.mutex.Unlock()

	for _, v := range cfg.Server {
		l := newListener(v)
		go l.start()
		s.Listeners = append(s.Listeners, l)
	}

	servers = s
}

func newListener(srvCfg cfg.Server) *ListenerWrapper {

	config := net.ListenConfig{}
	ctx, cancel := context.WithCancel(context.Background())
	l, err := config.Listen(ctx, srvCfg.Scheme, srvCfg.Listen)
	if err != nil {
		log.Error("init listener failed.", err)
	}

	//todo: 根据server.pass字段
	var passFunc func() (net.Conn, error)

	if srvCfg.Pass != "" {
		//dial
		passFunc = func() (net.Conn, error) {
			dst, err := net.Dial(srvCfg.Scheme, srvCfg.Pass)
			return dst, err
		}
	}

	return &ListenerWrapper{
		Listen:   srvCfg.Listen,
		Listener: l,

		Context: ctx,
		Cancel:  cancel,

		PassFunc: passFunc,
	}
}

func (l *ListenerWrapper) start() {

	for {
		// Wait for a connection.
		conn, err := l.Listener.Accept()
		if err != nil {
			log.Error("listen failed.", err)
		}

		// Handle the connection in a new goroutine.
		go func(c net.Conn) {
			//defer c.Close()

			dst, err := l.PassFunc()
			if err != nil {
				log.Error("upstream failed.", err)
				io.WriteString(c, "upstream failed.")
			} else {
				go io.Copy(c, dst)
				io.Copy(dst, c)

				//_, err := io.Copy(dst, c)
				//log.Info(err.Error())
			}

		}(conn)
	}
}

func (l *ListenerWrapper) stop() {
	l.Listener.Close()
}
